<?php
declare (strict_types = 1);

namespace app\frontend\controller;

use app\frontend\model\Article;
use app\frontend\model\ArticleCategory;
use app\frontend\model\ArticleComment;
use app\frontend\model\ArticleContent;
use app\frontend\model\ArticleDoc;
use think\facade\Config;
use think\facade\Db;
use think\facade\Filesystem;
use think\facade\Validate;

class MyArticle extends Base
{
    // 我的文章列表
    public function index()
    {
        return view();
    }

    // 文章列表数据接口
    public function list()
    {
        $page = request()->param('page');
        $limit = request()->param('limit');
        $title = request()->param('title');

        $articleList = Article::with(['articleCategory'])
            ->field('id,article_category_id,title,status,create_time,update_time')
            ->where([
                ['title', 'like', '%'.$title.'%'],
                ['user_id', '=', session('userInfo.id')]
            ])
            ->paginate([
                'list_rows' => $limit,
                'var_page' => 'page',
                'page' => $page,
                'query' => [
                    'title' => $title,
                ]
            ]);
        $articleListData = $articleList->toArray()['data'];
        // 设置顶级分类
        foreach ($articleListData as &$v) {
            if ($v['article_category_id'] == 0) {
                $v['category'] = '顶级分类';
            }
        }
        unset($v);

        $data = [
            'code' => 0,
            'msg' => '',
            'count' => $articleList->total(),
            'data' => $articleListData
        ];

        return json($data);
    }

    // 添加文章页面
    public function add()
    {
        $categoryList = ArticleCategory::field('id,pid,title,level')->select()->toArray();
        $categoryList = get_cate_list($categoryList);

        // 给分类列表加上空格以区分父子级关系
        $cate = [];
        $cate['_0'] = '顶级分类';
        foreach ($categoryList as $category) {
            $space = '';
            for ($i = 0; $i < (int)$category['level']; $i++) {
                $space .= '&emsp;';
            }
            $cate['_'.$category['id']] = $space . $category['title'];
        }

        return view('', [
            'category' => $cate
        ]);
    }

    // 富文本编辑器图片上传接口
    // 多图片上传
    public function uploadImg()
    {
        $files = request()->file();
        $saveName = [];
        try {
            validate(['image' => ['fileSize:1024000', 'fileExt:jpg,png,gif,jpeg']])
                ->check($files);
            $ds = DIRECTORY_SEPARATOR;
            foreach($files as $file) {
                $saveName[] = $ds.'uploads'.$ds . Filesystem::disk('public')->putFile('image'.$ds.'temp', $file);
            }
        } catch (\think\exception\ValidateException $e) {
            return json([
                'errno' => 1,
                'data' => $e->getMessage()
            ]);
        }

        // 根据操作系统的不同对返回的saveName格式进行处理
        foreach ($saveName as &$v) {
            if ($ds == '/') {
                $v = str_replace('\\', $ds, $v);
            } else {
                $v = str_replace('/', $ds, $v);
            }
        }
        unset($v);

        return json([
            'errno' => 0,
            'data' => $saveName
        ]);
    }

    // 保存文章
    public function save()
    {
        $params['title'] = trim(input('post.title'));
        $params['content'] = trim(input('post.content'));
        $params['status'] = input('post.status');
        $params['category'] = ltrim(input('post.category'), '_');

        $validate = Validate::rule([
            'title' => 'require|max:100'
        ]);
        if (!$validate->check($params)) {
            return json([
                'code' => 1,
                'msg' => $validate->getError()
            ]);
        }

        // 处理富文本编辑器传来的文本内容
        $newContent = $this->processContent($params['content']);
        $userInfo = session('userInfo');

        // 将数据存入数据库
        Db::startTrans();
        try {
            $articleModel = Article::create([
                'user_id' => $userInfo['id'],
                'article_category_id' => $params['category'],
                'title' => $params['title'],
                'status' => $params['status'],
            ]);
            ArticleContent::create([
                'article_id' => $articleModel->id,
                'content' => htmlspecialchars($newContent)
            ]);

            // 添加文章es索引生成记录
            if ($params['status'] == 2) {
                ArticleDoc::create([
                    'article_id' => $articleModel->id
                ]);
            }

            // 提交事务
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            // 返回操作失败信息
            return json([
                'code' => 1,
                'msg' => '保存失败'
            ]);
        }

        return json([
            'code' => 0,
            'msg' => '保存成功'
        ]);
    }

    // 编辑文章页面
    public function edit()
    {
        $id = (int)input('get.id');

        $article = Article::find($id);
        $article->articleContent;
        $article->articleCategory;
        $articleItem = $article->toArray();
        if (empty($articleItem['articleCategory'])) {
            $articleItem['articleCategory'] = ['id' => '_0'];
        }

        $categoryList = ArticleCategory::field('id,pid,title,level')->select()->toArray();
        $categoryList = get_cate_list($categoryList);

        // 给分类列表加上空格以区分父子级关系
        $cate = [];
        $cate['_0'] = '顶级分类';
        foreach ($categoryList as $category) {
            $space = '';
            for ($i = 0; $i < (int)$category['level']; $i++) {
                $space .= '&emsp;';
            }
            $cate['_'.$category['id']] = $space . $category['title'];
        }

        // 获取该文章所拥有的所有评论
        $articleComment = ArticleComment::with(['user'])->where('article_id', $id)
            ->order('create_time', 'desc')
            ->select();
        if (!$articleComment->isEmpty()) {
            $articleComment = $articleComment->toArray();
        } else {
            $articleComment = [];
        }

        return view('', [
            'category' => $cate,
            'article' => $articleItem,
            'articleComment' => $articleComment
        ]);
    }

    // 编辑文章页面保存接口
    public function update()
    {
        $params['articleId'] = input('post.id');
        $params['title'] = trim(input('post.title'));
        $params['content'] = trim(input('post.content'));
        $params['status'] = input('post.status');
        $params['category'] = ltrim(input('post.category'), '_');

        $validate = Validate::rule([
            'title' => 'require|max:100'
        ]);
        if (!$validate->check($params)) {
            return json([
                'code' => 1,
                'msg' => $validate->getError()
            ]);
        }

        // 处理富文本编辑器传来的文本内容
        $newContent = $this->processContent($params['content']);
        // 找到原先content中存在但是富文本编辑器在本次编辑中删除的图片的url，然后删除该图片
        // 找到数据库中存储的content
        $oldContent = ArticleContent::where('article_id', $params['articleId'])->find();
        $oldContent = htmlspecialchars_decode($oldContent['content']);
        // 正则表达式匹配查找图片路径
        $pattern = '/<[img|IMG].*?src=[\'|\"](.*?(?:[\.gif|\.jpg|\.jpeg|\.png]))[\'|\"].*?[\/]?>/i';
        preg_match_all($pattern, $oldContent, $oldMatches);
        $oldImgs = $oldMatches[1];
        preg_match_all($pattern, $newContent, $newMatches);
        $newImgs = $newMatches[1];
        // 删除图片
        for ($i=0; $i < count($oldImgs); $i++) {
            if (!in_array($oldImgs[$i], $newImgs)) {
                unlink('.' . $oldImgs[$i]);
            }
        }

        // 将数据存入数据库
        Db::startTrans();
        try {
            // 更新article表
            $articleModel = Article::find($params['articleId']);
            if ($articleModel->user_id != session('userInfo.id')) {
                return json([
                    'code' => 2,
                    'msg' => '文章id错误'
                ]);
            }
            $articleModel->title = $params['title'];
            $articleModel->status = $params['status'];
            $articleModel->article_category_id = $params['category'];
            $articleModel->save();
            // 更新article_content表
            $articleContent = ArticleContent::where('article_id', $params['articleId'])->find();
            $articleContent->content =htmlspecialchars($newContent);
            $articleContent->save();

            // 添加文章es索引记录
            if ($params['status'] == 2) {
                $exist = ArticleDoc::where('article_id', $articleModel->id)->find();
                if (empty($exist)) {
                    // 如果不存在记录
                    ArticleDoc::create([
                        'article_id' => $articleModel->id
                    ]);
                }
            }

            // 提交事务
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            // 返回操作失败信息
            return json([
                'code' => 3,
                'msg' => '修改失败'
            ]);
        }

        return json([
            'code' => 0,
            'msg' => '修改成功'
        ]);
    }

    // 查看文章
    public function view()
    {
        $id = input('get.id');
        $article = Article::with(['articleContent', 'user'])
            ->field('id,user_id,title,create_time,update_time,up')
            ->find($id)->toArray();

        // 修改文章中图片路径
        $content = htmlspecialchars_decode($article['articleContent']['content']);
        $pattern = "/<img src=\"\/uploads\/image\//";
        $domain = Config::get('site.domain');
        $replacement = "<img src=\"{$domain}/uploads/image/";
        $content = preg_replace($pattern, $replacement, $content);

        // 获取该文章所拥有的评论
        $articleComment = ArticleComment::with(['user'])
            ->where('article_id', $id)
            ->order('create_time', 'desc')
            ->select();
        if (!$articleComment->isEmpty()) {
            $articleComment = $articleComment->toArray();
        } else {
            $articleComment = [];
        }

        return view('', [
            'id' => $id,
            'title' => $article['title'],
            'content' => $content,
            'author' => $article['author'],
            'createTime' => $article['create_time'],
            'updateTime' => $article['update_time'],
            'articleComment' => $articleComment
        ]);
    }

    // 删除文章
    public function delete()
    {
        $id = (int)trim(input('post.id', '', 'strip_tags'));

        Db::startTrans();
        try {
            $articleModel = Article::find($id);
            $articleModel->delete();

            $articleContentModel = ArticleContent::where('article_id', $id)->find();
            // 删除content中的图片
            $content = htmlspecialchars_decode($articleContentModel->content);
            // 正则表达式匹配查找图片路径
            $pattern = '/<[img|IMG].*?src=[\'|\"](.*?(?:[\.gif|\.jpg|\.jpeg|\.png]))[\'|\"].*?[\/]?>/i';
            preg_match_all($pattern, $content, $matches);
            $images = $matches[1];
            // 删除图片
            $ds = DIRECTORY_SEPARATOR;
            for ($i=0; $i < count($images); $i++) {
                // 根据操作系统的不同对对图片的url进行处理
                if ($ds == '/') {
                    $v = str_replace('\\', $ds, $images[$i]);
                } else {
                    $v = str_replace('/', $ds, $images[$i]);
                }
                // 对于上传的图片才需要删除，如果是网页图片，则不需要删除
                $isMatch = strpos($v, 'uploads'.$ds.'image'.$ds.'article');
                if ($isMatch != false) {
                    // 如果是上传的图片
                    unlink('.' . $v);
                }
            }
            $articleContentModel->delete();

            // 添加文章es索引记录
            ArticleDoc::create([
                'article_id' => $id,
                'status' => 2
            ]);

            // 删除该文章下的所有评论
            ArticleComment::destroy(function($query) use ($id){
                $query->where('article_id', $id);
            });

            // 提交事务
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            // 返回操作失败信息
            return json([
                'code' => 1,
                'msg' => '删除失败'
            ]);
        }

        return json([
            'code' => 0,
            'msg' => '删除成功'
        ]);
    }

    // 我的文章多选删除接口
    public function deleteMulti()
    {
        $ids = input('post.ids', '', 'strip_tags');

        foreach ($ids as $id) {
            Db::startTrans();
            try {
                $articleModel = Article::find($id);
                $articleModel->delete();

                $articleContentModel = ArticleContent::where('article_id', $id)->find();
                // 删除content中的图片
                $content = htmlspecialchars_decode($articleContentModel->content);
                // 正则表达式匹配查找图片路径
                $pattern = '/<[img|IMG].*?src=[\'|\"](.*?(?:[\.gif|\.jpg|\.jpeg|\.png]))[\'|\"].*?[\/]?>/i';
                preg_match_all($pattern, $content, $matches);
                $images = $matches[1];
                // 删除图片
                $ds = DIRECTORY_SEPARATOR;
                for ($i=0; $i < count($images); $i++) {
                    // 根据操作系统的不同对对图片的url进行处理
                    if ($ds == '/') {
                        $v = str_replace('\\', $ds, $images[$i]);
                    } else {
                        $v = str_replace('/', $ds, $images[$i]);
                    }
                    // 对于上传的图片才需要删除，如果是网页图片，则不需要删除
                    $isMatch = strpos($v, 'uploads'.$ds.'image'.$ds.'article');
                    if ($isMatch != false) {
                        // 如果是上传的图片
                        unlink('.' . $v);
                    }
                }
                $articleContentModel->delete();

                // 添加文章es索引记录
                ArticleDoc::create([
                    'article_id' => $id,
                    'status' => 2
                ]);

                // 删除对应文章下的所有评论
                ArticleComment::destroy(function($query) use ($id){
                    $query->where('article_id', $id);
                });

                // 提交事务
                Db::commit();
            } catch (\Exception $e) {
                // 回滚事务
                Db::rollback();
                // 返回操作失败信息
                return json([
                    'code' => 1,
                    'msg' => '删除失败'
                ]);
            }
        }

        return json([
            'code' => 0,
            'msg' => '删除成功'
        ]);
    }

    /**
     * 富文本编辑器文本内容处理
     * @param string $content 富文本编辑器文本内容
     * @return bool|mixed|null 处理的结果
     */
    private function processContent($content)
    {
        // 转移图片
        if (!empty($content)) {
            // 已经存在的图片
            $imgArray = [];
            // 完成处理的content
            $newContent = null;

            $ds = DIRECTORY_SEPARATOR;

            // 正则表达式匹配查找图片路径
            $pattern = '/<[img|IMG].*?src=[\'|\"](.*?(?:[\.gif|\.jpg|\.jpeg|\.png]))[\'|\"].*?[\/]?>/i';
            preg_match_all($pattern, $content, $matches);
            $count = count($matches[1]);
            for ($i=0; $i < $count; $i++) {
                $editorImg = $matches[1][$i];
                // 根据操作系统的不同对返回的saveName格式进行处理
                if ($ds == '/') {
                    $editorImg = str_replace('\\', $ds, $editorImg);
                } else {
                    $editorImg = str_replace('/', $ds, $editorImg);
                }
                // 判断是否是新上传的图片
                $position = stripos($editorImg, $ds."temp".$ds);
                if ($position > 0) {    // 新上传的图片走这里
                    // 将图片从临时temp文件夹中迁移到article文件夹中
                    // 传过来的临时文件路径为：/uploads/image/temp/20201030/d885cc3b24b184a7c631408b5e0f670e.jpg
                    // 要迁移的文件路径：/uploads/image/article/20201030/d885cc3b24b184a7c631408b5e0f670e.jpg
                    // 新建日期文件夹
                    $tempArray = explode($ds, $editorImg);
                    $imageFloder = '.'.$ds.'uploads'.$ds.'image'.$ds.'article'.$ds . $tempArray[4];
                    if (!is_dir($imageFloder)) {
                        mkdir($imageFloder, 0777, true);
                    }
                    $tempImg = '.' . $editorImg;
                    $newImg = str_replace($ds.'temp'.$ds, $ds.'article'.$ds, $tempImg);
                    // 转移图片
                    rename($tempImg, $newImg);
                } else {
                    // 已经存在的图片走这里
                    $imgArray[] = $editorImg;
                }
            }

            // 重新整理content中的图片路径
            $newContent = str_replace($ds.'temp'.$ds, $ds.'article'.$ds, $content);
            return $newContent;
        }

        return false;
    }
}
